package ru.compft.common.services;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.transaction.annotation.Transactional;
import ru.compft.common.data.AppUser;

import java.util.List;

/**
 * User: ASUS
 * Date: 19.06.12
 * Time: 20:45
 * Сервис работы с пользователями
 * По умолчанию все методы только для чтения
 */
@Transactional(readOnly = true)
public interface UserService extends UserDetailsService {
    /**
     * Аутентификация пользователя, по логин/паролю
     *
     * @param login
     * @param password
     * @return
     */
    AppUser authentication(String login, String password);

    /**
     * Поиск пользователя по ID
     * Кешируем возвращенный результат по ID
     *
     * @param userId
     * @return
     */
//    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_READ_USERS')")
    @PostFilter("isAuthenticated() and hasPermission(returnValue, 'READ')")
    @Cacheable(value = "users", key = "#userId")
    AppUser findUserById(Long userId);

    /**
     * Поиск пользователя по login
     * Кешируем возвращенный результат по login
     *
     * @param login
     * @return
     */
//    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_READ_USERS')")
//    @PostFilter("isAuthenticated() and hasPermission(returnValue, 'READ')")
    @Cacheable(value = "users", key = "#login")
    AppUser findUserByLogin(String login);

    /**
     * Получение списка всех пользователей системы
     * На данный метод имеют право только пользователи с определенными ролями
     * Кешируем возвращенный результат
     *
     * @return
     */
//    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_READ_USERS')")
//    @PostFilter("isAuthenticated() and hasPermission(filterObject, 'READ')")
    @Cacheable(value = "users")
    List<AppUser> getAllUsers();

    /**
     * Получение пользователей от определенного индекса (from) и определенного количества (count)
     *
     * @param from
     * @param count
     * @return
     */
//    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_READ_USERS')")
    @PostFilter("isAuthenticated() and hasPermission(filterObject, 'READ')")
    List<AppUser> getUsers(int from, int count);

    /**
     * Подсчитываем всех пользователей в системе
     *
     * @return
     */
//    @PreAuthorize("hasAnyRole('ROLE_ADMIN','ROLE_READ_USERS')")
    int countAllUsers();

    /**
     * Создание пользователя
     * Очистим весь кеш для пользователей.
     * В кеш помещать не будем, т.к. пользователь еще не создан и у него нет ID
     *
     * @param appUser
     * @return
     */
    @CacheEvict(value = "users", allEntries = true)
    AppUser addUser(AppUser appUser);

    /**
     * Изменение свойств пользователя
     * Очистим весь кеш для пользователей.
     * Полученный результат поместим в кеш по ID и Login.
     * Кеш по всем пользователям снова перечитается лишь при getAllUsers()
     *
     * @param user
     * @return
     */
    @PreAuthorize("isAuthenticated() and hasPermission(#user, 'WRITE')")
    @Caching(evict = {
            @CacheEvict(value = "users", allEntries = true)
    }, put = {
            @CachePut(value = "users", key = "#user.id"),
            @CachePut(value = "users", key = "#user.login")
    })
    AppUser updateUser(AppUser user);

    /**
     * Удаление пользователя
     * Очистим весь кеш для пользователей.
     * Кеш по всем пользователям снова перечитается лишь при getAllUsers()
     *
     * @param appUser
     * @return
     */
    @PreAuthorize("isAuthenticated() and hasPermission(#user, 'DELETE')")
    @CacheEvict(value = "users", allEntries = true)
    Boolean deleteUser(AppUser appUser);

    /**
     * Смена пароля для пользователя
     *
     * @param user
     * @param newPassword
     * @return
     */
    @PreAuthorize("isAuthenticated() and hasPermission(#user, 'WRITE')")
    @Caching(evict = {
            @CacheEvict(value = "users", allEntries = true)
    }, put = {
            @CachePut(value = "users", key = "#user.id"),
            @CachePut(value = "users", key = "#user.login")
    })
    AppUser changePassword(AppUser user, String newPassword);

    /**
     * Специальный метод очистки кеша
     *
     * @return
     */
//    @PreAuthorize("hasRole('ROLE_ADMIN')")
    @CacheEvict(value = "users", allEntries = true)
    boolean clearCache();
}
